package com.ankicoo.common.record;


import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;

import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.TargetDataLine;


import static cn.hutool.core.io.FileUtil.copyFile;

/**
 * Description: 录制
 *
 * @author : QCYANG
 * @date : 2021/7/19 15:36
 */
@Component
public class Recording {
    byte bts[] = new byte[10000];
    ByteArrayOutputStream baos = null;
    boolean stopflag;
    TargetDataLine td = null;
    ByteArrayInputStream bais = null;
    /** 定义音频输入流*/
    AudioInputStream ais = null;

    /**设置一个播放的标志*/
    Boolean playflag;

    /** 每次保存的最后的文件名*/
    File tarFile = null;
    AudioFormat af = null;

    // 定义源数据行,源数据行是可以写入数据的数据行。它充当其混频器的源。应用程序将音频字节写入源数据行，这样可处理字节缓冲并将它们传递给混频器。

    SourceDataLine sd = null;

    public void play() throws LineUnavailableException {
        af = getAudioFormat();
        DataLine.Info info = new DataLine.Info(TargetDataLine.class, af);
        td = (TargetDataLine) (AudioSystem.getLine(info));
        td.open(af);
        td.start();
        Record record = new Record();
        Thread t1 = new Thread(record);
        t1.start();
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        stop();
        save();
    }

    // 停止录音
    public void stop() {
        stopflag = true;
    }

    private static AudioFormat getAudioFormat() {
        // 下面注释部分是另外一种音频格式，两者都可以
        AudioFormat.Encoding encoding = AudioFormat.Encoding.PCM_SIGNED;
        float rate = 8000f;
        int sampleSize = 16;
        boolean bigEndian = true;
        int channels = 1;
        return new AudioFormat(encoding, rate, sampleSize, channels, (sampleSize / 8) * channels, rate, bigEndian);
//		//采样率是每秒播放和录制的样本数
//		float sampleRate = 16000.0F;
//		// 采样率8000,11025,16000,22050,44100
//		//sampleSizeInBits表示每个具有此格式的声音样本中的位数
//		int sampleSizeInBits = 16;
//		// 8,16
//		int channels = 1;
//		// 单声道为1，立体声为2
//		boolean signed = true;
//		// true,false
//		boolean bigEndian = true;
//		// true,false
//		return new AudioFormat(sampleRate, sampleSizeInBits, channels, signed,bigEndian);
    }

    // 录音类，因为要用到MyRecord类中的变量，所以将其做成内部类
    class Record implements Runnable {
        // 定义存放录音的字节数组,作为缓冲区
        byte bts[] = new byte[10000];

        // 将字节数组包装到流里，最终存入到baos中
        // 重写run函数
        @Override
        public void run() {
            baos = new ByteArrayOutputStream();
            try {
                stopflag = false;
                while (stopflag != true) {
                    // 当停止录音没按下时，该线程一直执行
                    // 从数据行的输入缓冲区读取音频数据。
                    // 要读取bts.length长度的字节,cnt 是实际读取的字节数
                    int cnt = td.read(bts, 0, bts.length);
                    if (cnt > 0) {
                        baos.write(bts, 0, cnt);
                    }

                    // 开始从音频流中读取字节数
                    byte copyBts[] = bts;
                    bais = new ByteArrayInputStream(copyBts);
                    ais = new AudioInputStream(bais, af, copyBts.length / af.getFrameSize());
                    try {
                        DataLine.Info dataLineInfo = new DataLine.Info(SourceDataLine.class, af);
                        sd = (SourceDataLine) AudioSystem.getLine(dataLineInfo);
                        sd.open(af);
                        sd.start();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    // intBytes = -1;
                    // 关闭打开的字节数组流
                    if (baos != null) {
                        baos.close();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    // 下面这句td.drain()不能要，这样如果不播放数据就阻塞再次录音会出现其他程序访问错误
                    // td.drain();
                    td.close();
                    // 刷新显示波形的面板
                }
            }
        }

    }

    // 保存录音
    public void save() {
        af = getAudioFormat();
        byte audioData[] = baos.toByteArray();
        bais = new ByteArrayInputStream(audioData);
        ais = new AudioInputStream(bais, af, audioData.length / af.getFrameSize());
        // 定义最终保存的文件名
        File file = null;
        // 写入文件
        try {
            // 以当前的时间命名录音的名字
            // 将录音的文件存放到D盘下
            File filePath = new File("D:/");
            String tarPath = "D:/";
            if (!filePath.exists()) {// 如果文件不存在，则创建该目录
                filePath.mkdirs();
            }
            long time = System.currentTimeMillis();
            file = new File(filePath + "/" + time + ".wav");
            AudioSystem.write(ais, AudioFileFormat.Type.WAVE, file);
            // 将录音产生的wav文件转换为容量较小的mp3格式
            // 定义产生后文件名
//			tarFile = new File(tarPath + time + ".mp3");
//			Runtime run = null;
//			// 测试当前的路径
//
//			try {
//				run = Runtime.getRuntime();
//				// 调用编码器来将wav文件转换为mp3文件
//				// 把编码得到的mp3文件先存放到D盘下，然后利用文件拷贝函数将它放到指定的文件夹下同时将D盘下的文件删除
//				Process p = run
//						.exec("lame -b 16 " + filePath + "/" + file.getName() + " " + tarPath + tarFile.getName()); // 16为码率，可自行修改
//				// 释放进程
//				p.getOutputStream().close();
//				p.getInputStream().close();
//				p.getErrorStream().close();
//				// 等待
//				p.waitFor();
//
//				// 删除之前保存的的wav文件
//				if (file.exists()) {
//					file.delete();
//				}
//
            //定义最终要存放的文件路径
            String destPath = "D:/Program Files/apache-tomcat-6.0.35/webapps/XWZ/tempFile/";
            copyFile(tarPath+file.getName(), destPath);
//			} catch (Exception e) {
//				e.printStackTrace();
//			} finally {
//				// 最后都要执行的语句
//				// run调用lame解码器最后释放内存
//				run.freeMemory();
//			}

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 关闭流
            try {

                if (bais != null) {
                    bais.close();
                }
                if (ais != null) {
                    ais.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}
